#pragma once

/*
  NOTE:

  HANDMADE_INTERNAL:
    0 - Build for public release
    1 - Build for developer only

  HANDMADE_SLOW:
    0 - Not slow code allowed!
    1 - Slow code welcome.
*/

#if HANDMADE_SLOW
#define Assert(expression) if (!(expression)) { *(int *)0 = 0; }
#else
#define Assert(expression)
#endif

#define Kilobytes(value) ((value) * 1024LL)
#define Megabytes(value) (Kilobytes(value) * 1024LL)
#define Gigabytes(value) (Megabytes(value) * 1024LL)
#define Terabytes(value) (Gigabytes(value) * 1024LL)

#define ArrayCount(array) (sizeof(array) / sizeof((array)[0]))

inline uint32 SafeTruncateUInt64(uint64 value)
{
    Assert(value <= 0xFFFFFFFF);
    uint32 result = (uint32)value;
    return result;
}

#if HANDMADE_INTERNAL
struct debug_read_file_result
{
    uint32 contentSize;
    void* contents;
};

INTERNAL debug_read_file_result DEBUGPlatformReadEntireFile(char* filename);
INTERNAL void DEBUGPlatformFreeFileMemory(void* memory);
INTERNAL bool32 DEBUGPlatformWriteEntireFile(char* filename,uint32 memorySize, void *memory);
#endif

/*
  TODO: Services that the platform layer provides to the game
*/

/*
  NOTE: Services that the game provides to the platform layer.
  (this may expand in the future - sound on separate thread, etc.)
*/

// FOUR THINGS -timing, ontroller/keyboard input, bitmap buffer to use, sound buffer to use

struct game_offscreen_buffer
{
    // Pixels are alwasy 32-bits wide,Memory Order BB GG RR XX
    void *memory;
    int width;
    int height;
    int pitch;
};

struct game_sound_output_buffer
{
    int samplesPerSecond;
    int sampleCount;
    int16* samples;
};

struct game_button_state
{
    int halfTransitionCount;
    bool32 endedDown;
};

struct game_controller_input
{
    bool32 isConnected;
    bool32 isAnalog;
    real32 stickAverageX;
    real32 stickAverageY;

    union
    {
        game_button_state buttons[12];
        struct
        {
            game_button_state moveUp;
            game_button_state moveDown;
            game_button_state moveLeft;
            game_button_state moveRight;

            game_button_state actionUp;
            game_button_state actionDown;
            game_button_state actionLeft;
            game_button_state actionRight;

            game_button_state leftShoulder;
            game_button_state rightShoulder;

            game_button_state back;
            game_button_state start;

            game_button_state terminator;
        };
    };
};

struct game_input
{
    game_controller_input controllers[5];
};

inline game_controller_input* GetController(game_input* input, int controllerIndex)
{
    Assert(controllerIndex < ArrayCount(input->controllers));

    game_controller_input* result = &input->controllers[controllerIndex];
    return result;
}

struct game_memory
{
    bool32 isInitialized;

    uint64 permanentStorageSize;
    void* permanentStorage;

    uint64 transientStorageSize;
    void* transientStorage;
};

INTERNAL void GameUpdateAndRender(game_memory* memory, game_input *input, const game_offscreen_buffer* buffer);

INTERNAL void GameGetSoundSamples(game_memory* memory, game_sound_output_buffer* soundBuffer);

struct game_state
{
    int toneHz;
    int greenOffset;
    int blueOffset;
};